#include "board.h"
#include "resource.h"
#include <stdio.h>
#include <windows.h>
#include <Windowsx.h>

enum
{
	APP_MENU_GAME_EXIT = WM_APP,
	APP_MENU_GAME_RESTART,
	APP_MENU_GAME_CLEARSTATS,
	APP_MENU_GAME_TOGGLEAI,
	APP_MENU_HELP_ABOUT
};

/* Global Variables */
HBITMAP hBitmapX = NULL;
HBITMAP hBitmapO = NULL;
HMENU	hGameSubMenu = NULL;

/* Function Prototypes */
int Execute(void);

BOOL CALLBACK AboutDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
        case WM_INITDIALOG:
		{

		}
		break;

        case WM_COMMAND:
		{
            switch(LOWORD(wParam))
            {
                case IDOK:
                    EndDialog(hWnd, IDOK);
                break;
                case IDCANCEL:
                    EndDialog(hWnd, IDCANCEL);
                break;
				default:
					return FALSE;
            }
		}
        break;

        default:
            return FALSE;
    }
    return TRUE;
}

LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	LRESULT result = 0;
	//char str[32];
	int i;

	switch (uMsg)
    {
		case WM_CREATE:
		{
			hBitmapX = (HBITMAP)LoadImage(NULL, "X.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
			hBitmapO = (HBITMAP)LoadImage(NULL, "O.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
		}
		break;

		case WM_DESTROY:
		{
			PostQuitMessage(0);
			DeleteObject(hBitmapX);
			DeleteObject(hBitmapO);
		}
		break;

		case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
			HDC hdc_X = CreateCompatibleDC(hdc);
			HDC hdc_O = CreateCompatibleDC(hdc);

			HBRUSH hBrushGameBackground = CreateSolidBrush((COLORREF)RGB(192,192,192)); /* Grey */
			HBRUSH hBrushInfoBackground = CreateSolidBrush((COLORREF)RGB(255,255,255)); /* White */
			HBRUSH hBrushForeground = CreateSolidBrush((COLORREF)RGB(0,0,0)); /* Black */
			
			/* Paint the Game background */
			ps.rcPaint.left = CLIENT_WINDOW_GAME_X_LEFT;
			ps.rcPaint.right = CLIENT_WINDOW_GAME_X_RIGHT;
			ps.rcPaint.top = CLIENT_WINDOW_GAME_Y_TOP;
			ps.rcPaint.bottom = CLIENT_WINDOW_GAME_Y_BOTTOM;
            FillRect(hdc, &ps.rcPaint, hBrushGameBackground);

			/* Paint left vertical line */
			ps.rcPaint.left = 98;
			ps.rcPaint.right = 103;
			ps.rcPaint.top = CLIENT_WINDOW_GAME_Y_TOP;
			ps.rcPaint.bottom = CLIENT_WINDOW_GAME_Y_BOTTOM;
            FillRect(hdc, &ps.rcPaint, hBrushForeground);

			/* Paint right vertical line */
			ps.rcPaint.left = 198;
			ps.rcPaint.right = 203;
			ps.rcPaint.top = CLIENT_WINDOW_GAME_Y_TOP;
			ps.rcPaint.bottom = CLIENT_WINDOW_GAME_Y_BOTTOM;
            FillRect(hdc, &ps.rcPaint, hBrushForeground);

			/* Paint top horizontal line */
			ps.rcPaint.left = CLIENT_WINDOW_GAME_X_LEFT;
			ps.rcPaint.right = CLIENT_WINDOW_GAME_X_RIGHT;
			ps.rcPaint.top = 98;
			ps.rcPaint.bottom = 103;
            FillRect(hdc, &ps.rcPaint, hBrushForeground);

			/* Paint bottom horizontal line */
			ps.rcPaint.left = CLIENT_WINDOW_GAME_X_LEFT;
			ps.rcPaint.right = CLIENT_WINDOW_GAME_X_RIGHT;
			ps.rcPaint.top = 198;
			ps.rcPaint.bottom = 203;
            FillRect(hdc, &ps.rcPaint, hBrushForeground);

			/* Paint X and O pieces */
			SelectObject(hdc_X, hBitmapX);
			SelectObject(hdc_O, hBitmapO);
			for(i=0; i<NUMSLOTS; i++)
			{
				if(GetOccupation(i+1) == PLAYER_X)
				{
					/* Draw an X */
					BitBlt(hdc,
						((i%3)*100)+3, ((i/3)*100)+3,
						94, 94,
						hdc_X,
						0, 0,
						SRCCOPY);
				}
				else if(GetOccupation(i+1) == PLAYER_O)
				{
					/* Draw an O */
					BitBlt(hdc,
						((i%3)*100)+3, ((i/3)*100)+3,
						94, 94,
						hdc_O,
						0, 0,
						SRCCOPY);
				}
			}

			/* Paint the Info background */
			ps.rcPaint.left = CLIENT_WINDOW_INFO_X_LEFT;
			ps.rcPaint.right = CLIENT_WINDOW_INFO_X_RIGHT;
			ps.rcPaint.top = CLIENT_WINDOW_INFO_Y_TOP;
			ps.rcPaint.bottom = CLIENT_WINDOW_INFO_Y_BOTTOM;
            FillRect(hdc, &ps.rcPaint, hBrushInfoBackground);

			/* Paint the Info section separation line */
			ps.rcPaint.left = CLIENT_WINDOW_INFO_X_LEFT;
			ps.rcPaint.right = CLIENT_WINDOW_INFO_X_RIGHT;
			ps.rcPaint.top = CLIENT_WINDOW_INFO_Y_TOP;
			ps.rcPaint.bottom = CLIENT_WINDOW_INFO_Y_TOP + 2;
            FillRect(hdc, &ps.rcPaint, hBrushForeground);

			/* Draw the Info text */
			ps.rcPaint.left = CLIENT_WINDOW_INFO_X_LEFT;
			ps.rcPaint.right = CLIENT_WINDOW_INFO_X_RIGHT;
			ps.rcPaint.top = CLIENT_WINDOW_INFO_Y_TOP + 2;
			ps.rcPaint.bottom = CLIENT_WINDOW_INFO_Y_TOP + 2 + 20;
            DrawText(hdc, GetInfoString(), -1, &ps.rcPaint, DT_LEFT);

			/* Draw the Wins text */
			ps.rcPaint.left = CLIENT_WINDOW_INFO_X_LEFT;
			ps.rcPaint.right = CLIENT_WINDOW_INFO_X_RIGHT;
			ps.rcPaint.top = CLIENT_WINDOW_INFO_Y_TOP + 2 + 20;
			ps.rcPaint.bottom = CLIENT_WINDOW_INFO_Y_BOTTOM;
            DrawText(hdc, GetWinsString(), -1, &ps.rcPaint, DT_LEFT);

			/* Tidy up before calling EndPaint */
			DeleteObject(hBrushGameBackground);
			DeleteObject(hBrushForeground);
			DeleteObject(hBrushInfoBackground);
			DeleteDC(hdc_X);
			DeleteDC(hdc_O);

            EndPaint(hWnd, &ps);
        }
        break;

		case WM_COMMAND:
		{
			switch(LOWORD(wParam))
			{
				case APP_MENU_GAME_EXIT:
				{
					if(IDYES == MessageBox(hWnd, "Exit Game?", "Confirm", MB_YESNO|MB_ICONINFORMATION|MB_DEFBUTTON2))
					{
						PostQuitMessage(0);
					}
				}
				break;

				case APP_MENU_GAME_RESTART:
				{
					// Restart Game
					RestartGame();
					InvalidateRect(hWnd, NULL, FALSE);
				}
				break;

				case APP_MENU_GAME_CLEARSTATS:
				{
					ClearStats();
					InvalidateRect(hWnd, NULL, FALSE);
				}
				break;

				case APP_MENU_GAME_TOGGLEAI:
				{
					if(ToggleAIActive())
					{
						CheckMenuItem(hGameSubMenu, APP_MENU_GAME_TOGGLEAI, MF_CHECKED);
					}
					else
					{
						CheckMenuItem(hGameSubMenu, APP_MENU_GAME_TOGGLEAI, MF_UNCHECKED);
					}
				}
				break;

				case APP_MENU_HELP_ABOUT:
				{
					int ret = DialogBox(GetModuleHandle(NULL), 
						MAKEINTRESOURCE(IDD_HELP_ABOUT_DIALOG), hWnd, AboutDlgProc);
					if(ret == -1)
					{
						MessageBox(hWnd, "Dialog failed!", "Error",
							MB_OK | MB_ICONINFORMATION);
					}
				}
				break;

				default:
				{
					return DefWindowProc(hWnd, uMsg, wParam, lParam);
				}
				break;
			}
		}
		break;

		case WM_LBUTTONDOWN:
		{
			if(GetGameState() == IN_PROGRESS)
			{
				PlayerMove(GetBoardSlotFromCoords((unsigned int)GET_X_LPARAM(lParam),(unsigned int)GET_Y_LPARAM(lParam)), PLAYER_X);
				CheckForWin();
				if(GetAIActiveStatus() && GetGameState() == IN_PROGRESS)
				{
					AI_Move();
					CheckForWin();
				}
			}
			else
			{
				RestartGame();
			}
			InvalidateRect(hWnd, NULL, FALSE);
		}
		break;

		case WM_RBUTTONDOWN:
		{
			if(!GetAIActiveStatus())
			{
				if(GetGameState() == IN_PROGRESS)
				{
					PlayerMove(GetBoardSlotFromCoords((unsigned int)GET_X_LPARAM(lParam),(unsigned int)GET_Y_LPARAM(lParam)), PLAYER_O);
					CheckForWin();
				}
				else
				{
					RestartGame();
				}
				InvalidateRect(hWnd, NULL, FALSE);
			}
		}
		break;

		default:
		{
			return DefWindowProc(hWnd, uMsg, wParam, lParam);
		}
		break;
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	WNDCLASSEX	wndClass;
	HWND	hWnd;
	HMENU	hMainMenu;
	HMENU	hHelpSubMenu;
	RECT	rcClient;
	RECT	rcWindow;
	POINT	ptDiff;

	/* Create Window Class */
	wndClass.cbSize = sizeof(WNDCLASSEX);
	wndClass.style = 0;
	wndClass.lpfnWndProc = windowProc;
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.hInstance = hInstance;
	wndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
	wndClass.hIconSm = (HICON)LoadImage(NULL, "tictactoe.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
	wndClass.hCursor = LoadCursor(hInstance, IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH) GetSysColorBrush(COLOR_WINDOW);
	wndClass.lpszMenuName = NULL;
	wndClass.lpszClassName = "TicTacToeGameWindow";

	/* Register the Window Class */
	if(!RegisterClassEx(&wndClass))
	{
		MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	/* Create the Window */
	hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, "TicTacToeGameWindow", "Tic Tac Toe",
		CS_HREDRAW | CS_VREDRAW | WS_SYSMENU,
		560, 240, CLIENT_WINDOW_INFO_X_RIGHT, CLIENT_WINDOW_INFO_Y_BOTTOM,
		NULL, NULL, hInstance, NULL);

	if(hWnd == NULL)
	{
		MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	/* Create the menu items */
	
	hGameSubMenu = CreatePopupMenu();
	AppendMenu(hGameSubMenu, MF_STRING, APP_MENU_GAME_RESTART, "Restart");
	AppendMenu(hGameSubMenu, MF_STRING, APP_MENU_GAME_CLEARSTATS, "Clear Stats");
	AppendMenu(hGameSubMenu, MF_STRING, APP_MENU_GAME_TOGGLEAI, "Toggle AI");
	CheckMenuItem(hGameSubMenu, APP_MENU_GAME_TOGGLEAI, MF_UNCHECKED);
	AppendMenu(hGameSubMenu, MF_STRING, APP_MENU_GAME_EXIT, "Exit");

	hHelpSubMenu = CreatePopupMenu();
	AppendMenu(hHelpSubMenu, MF_STRING, APP_MENU_HELP_ABOUT, "About");

	hMainMenu = CreateMenu();
	AppendMenu(hMainMenu, MF_STRING | MF_POPUP, (UINT)hGameSubMenu, "Game");
	AppendMenu(hMainMenu, MF_STRING | MF_POPUP, (UINT)hHelpSubMenu, "Help");
	SetMenu(hWnd, hMainMenu);

	/* Adjust to the right size */
	GetClientRect(hWnd, &rcClient);
	GetWindowRect(hWnd, &rcWindow);
	ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
	ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
	MoveWindow(hWnd,rcWindow.left, rcWindow.top, CLIENT_WINDOW_INFO_X_RIGHT + ptDiff.x, CLIENT_WINDOW_INFO_Y_BOTTOM + ptDiff.y, TRUE);

	/* Load the Board */
	CreateNewBoard();
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	/* Run the Game */
	return Execute();
}

int Execute(void)
{
	MSG msg;
	
	/* Constantly update the board */
	while(GetMessage(&msg, NULL, 0, 0) > 0)
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return msg.wParam;
}
